package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lkd.common.VMSystem;
import com.lkd.config.TopicConfig;
import com.lkd.contract.*;
import com.lkd.dao.ChannelDao;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.ChannelEntity;
import com.lkd.entity.SkuEntity;
import com.lkd.entity.VendingMachineEntity;
import com.lkd.entity.VendoutRunningEntity;
import com.lkd.exception.LogicException;
import com.lkd.http.controller.vo.ChannelConfigReq;
import com.lkd.service.ChannelService;
import com.lkd.service.SkuService;
import com.lkd.service.VendingMachineService;
import com.lkd.service.VendoutRunningService;
import com.lkd.vo.ChannelVO;
import com.lkd.vo.Pager;
import com.lkd.vo.SkuVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Service
public class ChannelServiceImpl extends ServiceImpl<ChannelDao, ChannelEntity> implements ChannelService {


    @Override
    public Pager<ChannelEntity> findPage(long pageIndex, long pageSize, Map searchMap) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<ChannelEntity> page =
                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageIndex,pageSize);

        QueryWrapper queryWrapper=new QueryWrapper();
        if(searchMap!=null){
            queryWrapper.allEq(searchMap);
        }
        this.page(page,queryWrapper);

        Pager<ChannelEntity> pageResult = new Pager<>();
        pageResult.setCurrentPageRecords(page.getRecords());
        pageResult.setPageIndex(page.getCurrent());
        pageResult.setPageSize(page.getSize());
        pageResult.setTotalCount(page.getTotal());
        return pageResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void supply(SupplyContract supplyContract) {
        String innerCode = supplyContract.getInnerCode();

        List<SupplyChannel> supplyData = supplyContract.getSupplyData();

        for (SupplyChannel supplyChannel : supplyData) {
//        update tb_channel set current_capacity= current_capacity + ? where channelcode=? and skuId=?
            LambdaUpdateWrapper<ChannelEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper
                    .eq(ChannelEntity::getChannelCode,supplyChannel.getChannelCode())
                    .eq(ChannelEntity::getSkuId,supplyChannel.getSkuId())
                    .setSql(" current_capacity = current_capacity + " + supplyChannel.getCapacity());
            update(updateWrapper);
        }
    }

    /**
     * 查询当前sku是否有库存
     * @param innerCode
     * @param skuId
     * @return
     */
    @Override
    public ChannelVO hasCapacity(String innerCode, Long skuId) {

        List<ChannelEntity> channelEntityList = lambdaQuery()
                .eq(ChannelEntity::getInnerCode, innerCode)
                .eq(ChannelEntity::getSkuId, skuId)
                .gt(ChannelEntity::getCurrentCapacity, 0)
                .list();
        if(CollectionUtils.isEmpty(channelEntityList)){
            log.info("没有商品数据");
            return null;
        }
        return channelEntityList.stream().findFirst().map(channel -> {
            ChannelVO channelVO = new ChannelVO();
            BeanUtils.copyProperties(channel, channelVO);
            SkuVO skuVO = new SkuVO();
            BeanUtils.copyProperties(channel.getSku(),skuVO);
            channelVO.setSku(skuVO);
            return channelVO;
        }).get();
    }

    @Autowired
    private VendingMachineService machineService;
    @Autowired
    private VendoutRunningService runningService;
    @Autowired
    private MqttProducer mqttProducer;
    /**
     * 处理出货业务
     * @param vendoutContract
     */
    @Override
    public void vendout(VendoutContract vendoutContract) {
        String innerCode = vendoutContract.getInnerCode();
        VendoutData vendoutData = vendoutContract.getVendoutData();
        long skuId = vendoutData.getSkuId();
        String orderNo = vendoutData.getOrderNo();
//        查询收货机数据,正在运营的
        VendingMachineEntity machineEntity = machineService.lambdaQuery()
                .eq(VendingMachineEntity::getInnerCode, innerCode)
                .eq(VendingMachineEntity::getVmStatus, VMSystem.VM_STATUS_RUNNING)
                .one();
        if(machineEntity == null){
            log.error("没有售货机数据");
            return ;
        }
//        查询包含商品的有库存货道数据
        List<ChannelEntity> channelList = lambdaQuery()
                .eq(ChannelEntity::getInnerCode, innerCode)
                .eq(ChannelEntity::getSkuId, skuId)
                .gt(ChannelEntity::getCurrentCapacity, 0)
                .list();
        ChannelEntity vendoutChannel = null;
//        货道商品库存的递减
        for (ChannelEntity channel : channelList) {

            boolean b = lambdaUpdate()
                    .eq(ChannelEntity::getChannelId, channel.getChannelId())
                    .eq(ChannelEntity::getSkuId, skuId)
//                    .set(ChannelEntity::getCurrentCapacity,channel.getCurrentCapacity() -1)
                    .setSql(" current_capacity = current_capacity -1").update();
            if(b){
//                出货成功，给变量赋值
                vendoutChannel = channel;
                break;
            }else{
                continue;
            }
        }
        if(vendoutChannel == null){
//            减库存失败
            log.error("减库存失败");
//            TODO 通知订单服务，退款
            return;
        }
//        记录出货流水
        VendoutRunningEntity runningEntity = new VendoutRunningEntity();
        runningEntity.setOrderNo(orderNo);
        runningEntity.setSkuId(skuId);
        runningEntity.setStatus(false);
        runningEntity.setInnerCode(innerCode);
        runningEntity.setPrice(vendoutChannel.getPrice());
        runningEntity.setSkuName(vendoutChannel.getSku().getSkuName());
        boolean b = runningService.save(runningEntity);
//        发送出货消息给售货机终端

        try{
//            获取当前售货机终端的TOPIC
            String topic = TopicConfig.getVendoutTopic(innerCode);
            vendoutData.setChannelCode(vendoutChannel.getChannelCode());
            vendoutContract.setVendoutData(vendoutData);
            mqttProducer.send(topic,2,vendoutContract);
        }catch (Exception e){
            log.error("发送出货消息失败");
            e.printStackTrace();
        }
    }

    /**
     * 处理出货结果通知
     * @param vendoutResultContract
     */
    @Override
    public void vendoutResult(VendoutResultContract vendoutResultContract) {

        String innerCode = vendoutResultContract.getInnerCode();
        boolean success = vendoutResultContract.isSuccess();
        VendoutData vendoutData = vendoutResultContract.getVendoutData();
//        成功，修改出货流水状态
        if(success){
            runningService
                    .lambdaUpdate()
                    .eq(VendoutRunningEntity::getInnerCode,innerCode)
                    .eq(VendoutRunningEntity::getOrderNo,vendoutData.getOrderNo())
                    .set(VendoutRunningEntity::getStatus,true)
                    .set(VendoutRunningEntity::getUpdateTime, LocalDateTime.now())
                    .update();
        }else {
//        失败，恢复货道的库存
            String channelCode = vendoutData.getChannelCode();
            boolean b = lambdaUpdate()
                    .eq(ChannelEntity::getChannelCode, channelCode)
                    .eq(ChannelEntity::getInnerCode,innerCode)
                    .eq(ChannelEntity::getSkuId, vendoutData.getSkuId())
                    .setSql(" current_capacity = current_capacity + 1")
                    .update();
        }
    }

    @Override
    public List<ChannelEntity> getChannelesByInnerCode(String innerCode) {
        LambdaQueryWrapper<ChannelEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ChannelEntity::getInnerCode,innerCode);

        return this.list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean channelConfig(ChannelConfigReq channelConfig) {
          channelConfig.getChannelList().forEach(c->
                                           configSku(channelConfig.getInnerCode(),
                                                   c.getChannelCode(),
                                                   c.getSkuId()));
          return true;
    }

    @Override
    public ChannelEntity getChannelInfo(String innerCode, String channelCode) {
        LambdaQueryWrapper<ChannelEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(ChannelEntity::getInnerCode,innerCode)
                .eq(ChannelEntity::getChannelCode,channelCode);
        return this.getOne(queryWrapper);
    }

    @Autowired
    private SkuService skuService;

    /**
     * 设置商品
     * @param innerCode
     * @param channelCode
     * @param skuId
     * @return
     */
    private boolean configSku(String innerCode, String channelCode, Long skuId) {

        if(skuId<=0){
            return false;
        }
        SkuEntity skuEntity = skuService.getById(skuId); //查询商品
        if(skuEntity==null){
            return false;
        }

        ChannelEntity channel = this.getChannelInfo(innerCode,channelCode);
        if(channel == null){
            throw new LogicException("该货道不存在");
        }
        channel.setSkuId(skuId);
        channel.setPrice(skuEntity.getPrice());
        return this.updateById(channel);
    }
}
